/*
 *
 *
Copyright (c) 1998-2001 Aristar, Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. The end-user documentation included with the redistribution, if any,
must include the following acknowledgment:

"This product includes software developed by Aristar, Inc. (http://www.aristar.com/)."

Alternately, this acknowledgment may appear in the software itself, if and
wherever such third-party acknowledgments normally appear.

4. The names "Dialect" and "Aristar, Inc." must not be used to endorse or
promote products derived from this software without prior written permission.
For written permission, please contact info@aristar.com.

5. Products derived from this software may not be called "Dialect", nor may
"Dialect" appear in their name, without prior written permission of Aristar, Inc.

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
ARISTAR, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software consists of voluntary contributions made by many individuals
on behalf of Aristar, Inc.  For more information on Aristar, Inc.,
please see <http://www.aristar.com/>.

Portions of this software are based upon software freely available and
written by individuals not associated with Aristar, Inc.  Copyrights are
maintained in the relevant source code files.
 *
 *
 */

#ifndef CVALUE_H
#define CVALUE_H

#include "DConfigGlobals.h"

class CInterpreter;

////////////////////////////////////////////////////////////////////////
// Do not change these numbers!!!
// Or else previously serialized objects will be garbage
// These numbers are not numericaly equal to the TokenTypes enum
// which contain things like: stString, stInteger, etc.
// They do, however, symbolically correspond (eg. ST_STRING -> stString)
#define ST_STRING			1
#define ST_INTEGER			2
#define ST_FLOAT			3
#define ST_BOOLEAN			4
#define ST_FUNCTION			5
#define ST_ARRAY			6
#define ST_SYMBOL			7
#define ST_CLASS			8
#define ST_CLASS_INSTANCE	9
#define ST_NIL				10
#define ST_UNDEFINED		11
#define ST_FRAME			12
#define ST_FRAME_END		13
#define ST_PROPERTY			14
#define ST_CHUNK			15
#define ST_NOP				16	// Just an empty byte for padding
////////////////////////////////////////////////////////////////////////


// Serializing helper functions
class TFile;	// forward decl.
U8* SerializeInTString(U8* inBuffer, TString& string);
void SerializeOutTString(CFile* outFile, const TString& string);

U8* SerializeInInt(U8* inBuffer, int& val);
void SerializeOutInt(CFile* outFile, int val);

//===========================================================

#define FIND_NEXT_START		0
#define FIND_NEXT_INPROG	1
#define FIND_NEXT_FINISHED	2

typedef struct tagFindNextInfo {
	tagFindNextInfo():info(FIND_NEXT_START){};
	int info;		// FIND_NEXT_START || FIND_NEXT_INPROG || FIND_NEXT_FINISHED
	long data0;
	long data1;
} FindNextInfo;

//=======================================================

class CImplementer;		// Quick Prototypes only
class CArrayImpl;
class CChunkImpl;
class CFrameImpl;
class CFormImpl;
class CSymbolImpl;
class CFunctionImpl;
class CPropertyImpl;
class CClassImpl;
class CClassInstImpl;
class TFile;
class CInterpreter;
typedef struct tagFindNextInfo FindNextInfo;
class CByteCode;

class D_EXPORT VALUE {
public:
	TString StringValue;	// TString can't be in a union, and not private (for now)
private:
	// These must be private in order to ensure VALUE's built
	// in garbage collection can't be bypassed accidentally...
	SymbolTypes type;
	union {
		int IntegerValue;
		float FloatValue;
		bool BooleanValue;
		CImplementer* ci;
	};

//#ifdef _DEBUG
//	void __GARBAGE_COLLECT();
//#endif

public:
	const SymbolTypes Type() const{return (const SymbolTypes)type;};

	// Do not use ForceCI() unless you really, really need to.  And even then don't...
	void ForceCI(SymbolTypes t, CImplementer* pCI, bool bIncRefCount = true);

	// Default construct
	VALUE():type(stUndefined), ci(NULL){};
	// Destructor must decrement the ci->m_RefCount if valid, delete ci if == zero
	~VALUE();

	// Copy contructor (the ci->m_RefCount gets incremented here)
	VALUE(const VALUE& copy);
	VALUE operator=(const VALUE& x);

	// This for stFrame, stArray, and stInteger
	VALUE(SymbolTypes t, int arg = -1, const VALUE initEntries[] = NULL);
	VALUE(SymbolTypes t, int arg, const VALUE initEntry);

	// This for stSymbol, stString
	VALUE(SymbolTypes t, TString arg);

	// This for stBoolean and stNil
	VALUE(SymbolTypes t, bool arg = false);

	// This for stClass
	VALUE(SymbolTypes t, VALUE& baseClass, TString className);
	VALUE(CClassImpl* lpCoreClass);	// Only for C++ derived classes

	// For stClassInstance
	VALUE(SymbolTypes t, VALUE& baseClass, CInterpreter* pCreater);

	// This for properties
	VALUE(SymbolTypes t, VALUE readFunc, VALUE writeFunc, VALUE vInitial);

	// This for chunks
	VALUE(SymbolTypes t, int length, const U8* data);
	VALUE(SymbolTypes t, TString text, int encoding, int itype);

	// These two for stFunction
	VALUE(SymbolTypes t, CByteCode* code, TString paramList[], int paramCount);
	VALUE(SymbolTypes t, VALUE (*lpCoreFunc)(VALUE* self, int argCount, VALUE argVals[],
		CInterpreter* pInterp), TString moduleName);

	// These quick constructors are only for "pass by value" types
	VALUE(int x):type(stInteger), IntegerValue(x){};
	VALUE(float x):type(stFloat), FloatValue(x){};
	VALUE(bool x):type(stBoolean), BooleanValue(x){};
	VALUE(TString x):type(stString), StringValue(x), ci(NULL){};
	VALUE(LPCTSTR x):type(stString), StringValue(x), ci(NULL){};

	VALUE* FindValuePtr(const VALUE& key, bool bCreateOK);	// Intended for CInterpreter only!

	void SerializeIn(TString filename);
	void SerializeIn(TFile& inFile);
	void SerializeOut(TString filename);
	// The following two should become protected functions I suppose...
	U8* SerializeIn(U8* inBuffer);		// Requires the header to have been read
	void SerializeOut(CFile* outFile);	// Requires the header to have been written
#ifdef CRYPTO_SUPPORT
	// Used to encrypt/decrypt complete VALUEs at runtime
	VALUE SerializeOutMemory();
	bool SerializeInMemory(VALUE vChunkIn);
	bool SerializeInMemory(U8* pData, int length);	// This includes header unlike other SerializeIn(U8*)
#endif

public:
	VALUE Map(VALUE (*mapFunc)(VALUE& array));				// Array version
	VALUE Map(VALUE (*mapFunc)(VALUE& key, VALUE& value));	// Frame version
	VALUE Select(bool (*selectFunc)(VALUE& array));
	VALUE Sort(bool (*compareFunc)(VALUE& first, VALUE& second));
	bool Isa(TString type);
	TString TypeString() const;
	TString __unparse__();
	bool FindNext(FindNextInfo& fni, VALUE& value);
	bool FindNext(FindNextInfo& fni, VALUE& key, VALUE& value);
	int Length() const;
	void Resize(int newLength, VALUE init = VALUE());
	void Remove(const TString& key);
	VALUE Clone() const;
	VALUE DeepClone() const;
	//void DecRefCount();	// DANGER!!!

	VALUE Get(const VALUE& arg);
	void Set(const VALUE& indexer, const VALUE& arg);
	VALUE operator[] (const VALUE& arg) const;

	U8* GetChunkData();
	int GetChunkByteCount() const;
	bool CopyChunkProperties(VALUE vChunk);

	int Integer() const;
	float Float() const;
	bool Boolean() const;
	TString String() const;
	CArrayImpl* Array() const;
	CFrameImpl* Frame() const;
	CFormImpl* Form() const;
	CSymbolImpl* Symbol() const;
	CFunctionImpl* Function() const;
	CPropertyImpl* Property() const;
	CClassImpl* Class() const;
	CClassInstImpl* ClassInstance() const;
	CChunkImpl* Chunk() const;
	void* Void();

	VALUE operator + (VALUE& second);
	VALUE operator - ();	// Unary minus
	VALUE operator - (VALUE& second);
	VALUE operator * (VALUE& second);
	VALUE operator / (VALUE& second);
	VALUE operator > (VALUE& second);
	VALUE operator < (VALUE& second);
	VALUE operator >= (VALUE& second);
	VALUE operator <= (VALUE& second);
	VALUE operator != (VALUE& second);
	VALUE operator == (VALUE& second);
	VALUE operator && (VALUE& second);
	VALUE operator || (VALUE& second);
	VALUE operator ! ();	// Boolean Not
};

bool operator == (TString& first, VALUE& second);
bool operator != (TString& first, VALUE& second);

//=======================================================
// This used to be a class, be all functionality for it has been shifted else where...
// So now we just have it's member functions remaining.
// These functions may soon be replaced completely by
// VALUE constructor overloads.

D_EXPORT VALUE AllocVoid(void* ptr, void (*freeVoid)(void* pVoid), TString rttiName);
D_EXPORT inline VALUE AllocArray(int length, VALUE initEntries[] = NULL){return VALUE(stArray, length, initEntries);};
D_EXPORT inline VALUE AllocArray(int length, VALUE initEntry) {return VALUE(stArray, length, initEntry);}
D_EXPORT inline VALUE AllocFrame(int tableSize = 97){return VALUE(stFrame, tableSize);};
D_EXPORT inline VALUE AllocSymbol(TString name){return VALUE(stSymbol, name);};
D_EXPORT inline VALUE AllocProperty(VALUE readFunc, VALUE writeFunc, VALUE vInitial){return VALUE(stProperty, readFunc, writeFunc, vInitial);};
D_EXPORT inline VALUE AllocFunction(CByteCode* code, TString paramList[], int paramCount){return VALUE(stFunction, code, paramList, paramCount);};
D_EXPORT inline VALUE AllocFunction(VALUE (*lpCoreFunc)(VALUE* self, int argCount, VALUE argVals[], CInterpreter* pInterp), TString moduleName)
{
	return VALUE(stFunction, lpCoreFunc, moduleName);
};
D_EXPORT inline VALUE AllocClass(CClassImpl* lpCoreClass){return VALUE(lpCoreClass);};
D_EXPORT inline VALUE AllocClass(TString className, VALUE baseClass){return VALUE(stClass, baseClass, className);};
D_EXPORT inline VALUE AllocClassInstance(VALUE& baseClass, CInterpreter* pCreater){return VALUE(stClassInstance, baseClass, pCreater);};
D_EXPORT inline VALUE AllocNil(){return VALUE(stNil, false);};
D_EXPORT inline VALUE AllocChunk(int length, const U8* data){return VALUE(stChunk, length, data);}
D_EXPORT inline VALUE AllocChunk(TString text, int encoding, int itype){return VALUE(stChunk, text, encoding, itype);}


//=======================================================
#endif	// CVALUE_H
